' maxtk.editor

Strict

Import brl.maxutil

Import "host.bmx"
Import "options.bmx"
Import "help.bmx"
Import "outputpanel.bmx"
Import "requesters.bmx"
Import "projects.bmx"
Import "splitter.bmx"
Import "debugtree.bmx"
Import "opencode.bmx"

Type TRect
	Field		x,y,w,h

	Method Set(xpos,ypos,width,height)
		x=xpos;y=ypos;w=width;h=height
	End Method
	
	Method ToString$()
		Return ""+x+","+y+","+w+","+h
	End Method

	Method FromString(s$)
		Local	p,q,r
		p=s.Find(",")+1;If Not p Return
		q=s.Find(",",p)+1;If Not q Return
		r=s.Find(",",q)+1;If Not r Return
		x=Int(s[..p-1])
		y=Int(s[p..q-1])
		w=Int(s[q..r-1])
		h=Int(s[r..])
	End Method
	
	Method IsOutside(tx,ty,tw,th)
		If x+w<=tx Or y+h<=ty Return True
		If x>=tx+tw Or y>=ty+th Return True	
	End Method

End Type


Type THotkeyButton Extends TGadgetView
	Field capture:TGadget
	Field button:TGadget
	Field keycode,modifier
	Field button2:TGadget
	Field keycode2,modifier2
	Field pick,tag

	Function shortcut$(keycode,modifier)
		Local	m$
		If keycode>=KEY_0 And keycode<=KEY_9
			m$=Chr(keycode)
		ElseIf keycode>=KEY_A And keycode<=KEY_Z
			m$=Chr(keycode)
		ElseIf keycode>=KEY_F1 And keycode<=KEY_F12
			m$="F"+(keycode+1-KEY_F1)
		ElseIf keycode>=KEY_NUM0 And keycode<=KEY_NUM9
			m$="Num "+(keycode+1-KEY_NUM0)
		Else
			Select keycode
				Case KEY_LEFT m="Left"
				Case KEY_UP m="Up"
				Case KEY_RIGHT m="Right"
				Case KEY_DOWN m="Down"
				Case KEY_BACKSPACE m="Backspace"
				Case KEY_TAB m="Tab"
				Case KEY_CLEAR m="Clear"
				Case KEY_RETURN m="Enter"
				Case KEY_ESCAPE m="Escape"
				Case KEY_SPACE m="Space"
				Case KEY_PAGEUP m="PageUp"
				Case KEY_PAGEDOWN m="PageDown"
				Case KEY_END m="End"
				Case KEY_HOME m="Home"
				Case KEY_SELECT m="Select"
				Case KEY_PRINT m="Print"
				Case KEY_EXECUTE m="Exec"
'				Case KEY_SCREEN m="
				Case KEY_INSERT m="Insert"
				Case KEY_DELETE m="Delete"
				Case KEY_TILDE m="~~"
				Case KEY_MINUS m="-"
				Case KEY_EQUALS m="="
				Case KEY_OPENBRACKET m="["
				Case KEY_CLOSEBRACKET m="]"
				Case KEY_BACKSLASH m="\"
				Case KEY_SEMICOLON m=";"
				Case KEY_QUOTES m="'"
				Case KEY_COMMA m=","
				Case KEY_PERIOD m="."
				Case KEY_SLASH m="/"
				Case 220 m="\"
				Case 19,3 m="Break"	'Const KEY_PAUSE=19
'				Default
'					DebugLog "key="+keycode
			End Select
		EndIf				
		If m
			If modifier&1 m$="Shift+"+m$
			If modifier&8 m$="Apple"+m$	'apple key
			If modifier&4 m$="Alt+"+m$
			If modifier&2 m$="Ctrl+"+m$
		EndIf
'		If m="" m="undefined"
		Return m
	End Function

	Method SetHotkey(_keycode,_modifier)
		keycode=_keycode
		modifier=_modifier
		button.settext shortcut(_keycode,_modifier)
	End Method

	Method SetHotkey2(_keycode,_modifier)
		keycode2=_keycode
		modifier2=_modifier
		button2.settext shortcut(_keycode,_modifier)
	End Method

	Method onkeydown(k,m)
		If pick=0 Return
		If k>=KEY_LSHIFT And k<=KEY_RALT Return
		If k=KEY_LSYS Or k=KEY_RSYS Return
		If pick=1
			SetHotkey k,m
			ActivateGadget button				
		Else
			SetHotkey2 k,m
			ActivateGadget button2
		EndIf
		pick=0
	End Method

	Method OnEvent()
		Local k,m
		Select EventID()
			Case EVENT_GADGETACTION 
				If pick=1 SetHotkey 0,0;pick=0;Return
				If pick=2 SetHotkey2 0,0;pick=0;Return
				If EventSource()=button
					SetGadgetText button,"Press HotKey Now"
					pick=1
					ActivateGadget capture
				EndIf
				If EventSource()=button2
					SetGadgetText button2,"Press HotKey Now"					
					pick=2
					ActivateGadget capture
				EndIf
			Case EVENT_KEYDOWN
				If EventSource()=capture
					OnKeyDown EventData(),EventMods()
				EndIf
		End Select
	End Method

	Method ToString$()
		Return keycode+","+modifier+","+keycode2+","+modifier2
	End Method
	
	Method FromString(s$)
		Local p,q,_code,_modifier
		q=s.find(",",p)
		_code=Int s[p..q]
		p=q+1
		q=s.find(",",p)
		If q=-1 q=Len s
		_modifier=Int s[p..q]
		p=q+1
		SetHotkey _code,_modifier		
		q=s.find(",",p)
		If q>-1
			_code=Int s[p..q]
			p=q+1
			_modifier=Int s[p..]
			p=q+1
			SetHotkey2 _code,_modifier
		EndIf
		Dirty Null
	End Method
	
	Function hotkeycallback(event:TEvent,context:Object)
		Local this:THotkeyButton
		Local k,m				
		this=THotkeyButton(context)
		If this And event.id=EVENT_KEYDOWN
'			DebugLog "callback keydown"+event.data+":"+event.mods
			this.onkeydown(event.data,event.mods)
		EndIf
	End Function 
	
	Method CreateHotkeyButton:THotkeyButton(parent:TDataNode,name$,_keycode,_modifier)
		SetName name
		SetSize 240,24
		parent.Append Self		

		capture=CreatePanel(xpos,ypos,width,height,ParentGadget(),PANEL_ACTIVE)
'		SetPanelColor capture,0,255,0
		SetGadget capture
?macos		
		SetGadgetFilter capture,hotkeycallback,Self
?
		Local w=width/2
		button=CreateButton("..",0,0,w,height,capture,1)
		AddEventHandler button,Self
		button2=CreateButton("..",w,0,w,height,capture,1)
		AddEventHandler button2,Self

'		SetGadgetFilter button,filter
'		SetGadget CreateButton("..",xpos,ypos,width,height,ParentGadget(),1)
		SetHotkey _keycode,_modifier
		Return Self
	End Method

End Type


Type THotkeyOptions Extends TOptionsPage

	Field scrollpanel:TScrollPanel
	Field keylist:TList
	Field itemmap:TMap
	Field changed
	Field cwidth,cheight
	
	Method ShowPage()
		Super.ShowPage
		owner.host.DisableHotkeys
	End Method

	Method AddHotkeyButton:THotkeyButton(name$,hotkey,modifier)
		Local b:THotkeyButton
		b=New THotkeyButton.CreateHotkeyButton(scrollpanel.AddView(name),name,hotkey,modifier)
		Return b
	End Method

	Method CreateHotKeyOptions:THotKeyOptions(parent:TOptionsPage)
		SetName "Hotkeys"
		keylist=New TList
		itemmap=New TMap
		parent.AddPage Self
		scrollpanel=AddScrollPanel(width,height)
		InitHotkeys
		Return Self
	End Method
	
	Method Dirty(cause:TDataNode)	'called by editor.ReadConfig
		Local b:THotkeyButton
		b=THotkeyButton(cause)
		If b
			changed=True		
		EndIf
		Super.Dirty cause
	End Method
	
	Method FindHotkey:THotkeyButton(name$)
		Local b:THotkeyButton
		For b=EachIn keylist
			If b.name=name Return b
		Next
	End Method
		
	Method AddHotkey:THotkeyButton(name$,keycode=0,modifier=0,hotkey2=0,modifier2=0)
		Local k:THotkeyButton
'		k=scrollpanel.AddHotkeyButton(name,keycode,modifier)
		k=FindHotKey(name)
		If k
			k.SetHotkey2(keycode,modifier)		
		Else
			k=AddHotkeyButton(name,keycode,modifier)
			keylist.AddLast(k)	
		EndIf
		If hotkey2
			k.SetHotkey2(hotkey2,modifier2)
		EndIf
		Return k
	End Method

	Method AddMenuItem(name$,item:TGadget,tag)
		Local b:THotkeyButton
		b=FindHotkey(name)
		If b=Null b=AddHotKey(name)
		b.tag=tag
		itemmap.Insert(item,b)		
	End Method

	Method InitHotkeys()
?MacOS
		Const MENUMOD=MODIFIER_APPLE
?Win32
		Const MENUMOD=MODIFIER_CONTROL
?Linux
		Const MENUMOD=MODIFIER_CONTROL
?
		AddHotkey "New",KEY_N,MENUMOD
		AddHotkey "Open",KEY_O,MENUMOD
		AddHotkey "Close",KEY_W,MENUMOD,KEY_F4,MENUMOD
		AddHotkey "Save",KEY_S,MENUMOD
		AddHotkey "Save As",KEY_S,MENUMOD|MODIFIER_SHIFT
		AddHotkey "Save All"
		AddHotkey "Next File",KEY_RIGHT,MENUMOD
		AddHotkey "Previous File",KEY_LEFT,MENUMOD
		AddHotkey "IDE Options",KEY_O,MENUMOD|MODIFIER_SHIFT
		AddHotkey "Print"
		AddHotkey "Exit"

		AddHotkey "Undo",KEY_Z,MENUMOD		
		AddHotkey "Redo",KEY_Y,MENUMOD	'?macos KEY_Z,MENUMOD|MODIFIER_SHIFT
?MacOS
		AddHotkey "Redo",KEY_Z,MENUMOD|MODIFIER_SHIFT
?
		AddHotkey "Cut",KEY_X,MENUMOD
		AddHotkey "Copy",KEY_C,MENUMOD
		AddHotkey "Paste",KEY_V,MENUMOD
		AddHotkey "Select All",KEY_A,MENUMOD
		AddHotkey "Block Indent",KEY_CLOSEBRACKET,MENUMOD
		AddHotkey "Block Outdent",KEY_OPENBRACKET,MENUMOD
		AddHotkey "Find",KEY_F,MENUMOD

		AddHotkey "Find Next",KEY_F3
		AddHotkey "Replace",KEY_H,MENUMOD
		AddHotkey "Goto Line",KEY_G,MENUMOD
?MacOS
		AddHotkey "Find Next",KEY_G,MENUMOD
		AddHotkey "Replace",KEY_H,MENUMOD
		AddHotkey "Goto Line",KEY_L,MENUMOD
?
		AddHotkey "Build",KEY_B,MENUMOD
		AddHotkey "Build and Run",KEY_R,MENUMOD
		AddHotkey "Command Line"
		AddHotkey "Step",KEY_F9
		AddHotkey "Step In",KEY_F10
		AddHotkey "Step Out",KEY_F11
		AddHotkey "Halt"
		
		AddHotkey "Quick Build"
		AddHotkey "Debug Build"
		AddHotkey "Build GUI App"
		
		AddHotkey "Lock Build File"
		AddHotkey "Unlock Build File"
		AddHotkey "Manage Projects"
		
		AddHotkey "Quick Help",KEY_F1
		AddHotkey "Help Index",KEY_F2
		AddHotkey "Home"
		AddHotkey "Back"
		AddHotkey "Forward"
		AddHotkey "About"

		
	End Method
End Type

Type TEditorOptions Extends TOptionsPage
	Field	showtoolbar:TButton
	Field	restoreopenfiles:TButton
	Field	debuggeropenfiles:TButton
	Field	findfromcursor:TButton
'	Field	autobackup:TButton
'	Field	hideoutput:TButton
	Field	outputstyle:TGadgetStyle
	Field	errorstyle:TTextStyle
	Field	navstyle:TGadgetStyle
	Field	navside:TButton
'	Field	navswapbutton,navswap
'	Field	outputfontname$
'	Field	outputfontsize
'	Field	outputcolor:TColorButton
	
	Method CreateEditorOptions:TEditorOptions(parent:TOptionsPage)
		SetName "Editor Options"
		parent.AddPage Self
		showtoolbar=AddButton("Show ToolBar",2)
		showtoolbar.Set True
		restoreopenfiles=AddButton("Open Files At Startup",2)
		debuggeropenfiles=AddButton("Debugger Can Open Files",2)
		findfromcursor=AddButton("Find uses term under cursor",2)
'		autobackup=AddButton("Enable Archiving",2)
'		hideoutput=AddButton("Hide Output",2)
		outputstyle=AddGadgetStyle(Self,"Output Panel")
		errorstyle=AddTextStyle(outputstyle,"Error Text")
		navstyle=AddGadgetStyle(Self,"NavBar")		
		navside=AddButton("Navbar on left",2)		
		Return Self
	End Method
End Type


Type TEditor Extends THost

	Field	inifile$

	Field	panels:TToolPanel[]
	Field	helppanel:THelpPanel
	Field	currentpanel:TToolPanel
	Field	output:TOutputPanel
	Field	cmdlinereq:TCmdLineRequester
	Field	cmdline$
	Field	newrequester:TNewRequester
	Field	gotoreq:TGotoRequester
	Field	findreq:TFindRequester
	Field	replacereq:TReplaceRequester
'	Field	activerequester:TRequester moved to host
	Field	projectreq:TProjectRequester
'	Field	projectprops:TProjectProperties
	
	Field	menubar:TGadget,toolbar:TGadget,client:TGadget,tabbar:TGadget		'bars,botbar,publicwindow
	Field	vsplit:TSplitter
'	Field	hsplit:TSplitter
	Field	debugtree:TDebugTree

	Field	projects:TProjects
	Field	coderoot:TDataNode
	Field	navbar:TNavBar	

	Field	optionsreq:TOptionsRequester
	Field	hostoptions:TOptionsPage
	Field	options:TEditorOptions
	Field	hotkeys:THotkeyOptions

	Field	editormode
	Field	debugcode:TOpenCode

	Field	running
	Field	recentmenu:TGadget
	Field	recentfiles:TList=New TList
	Field	recentmenus:TGadget[]
	Field	openlist:TList=New TList
	Field	openlock$
	Field	projlist:TList=New TList
	Field	winsize:TRect=New TRect
	Field	winmax,tooly,vsplitpos,debugview,navtab	'hsplitpos,
	Field	progress

	Field	filemenu:TGadget,editmenu:TGadget,projectmenu:TGadget
	Field	toolsmenu:TGadget,helpmenu:TGadget,optionsmenu:TGadget

	Function eventhook:Object(id,data:Object,context:Object)
		Local event:TEvent
		Local editor:TEditor
		event=TEvent(data)
		If event
			CurrentEvent=event
			editor=TEditor(context)
			editor.OnEvent' event	
		EndIf
		Return data
	End Function

	Method Run()
'		AddHook EmitEventHook,eventhook,Self
		While running
			WaitEvent()
			OnEvent' event	
		Wend
	End Method
	
	Method OpenProgress(message$)
'		progress.Open message
'		DisableGadget window
		SetStatus message
		progress=-1
	End Method

	Method CloseProgress()
'		progress.Hide
		SetStatus ""
'		EnableGadget window
		progress=0
	End Method
	
	Method UpdateProgress(message$,value=0)		'returns false if cancelled
'		Return progress.Update(message,value)
		If progress
			If progress/5<>value/5
				SetStatus message+" "+value+"%"
				progress=value
				PollSystem
			EndIf
		EndIf
	End Method
	
	Method ShowFind(search$)
		If Not options.findfromcursor.selected() search=""
		findreq.showFind search
	End Method

	Method ReadConfig(inifile$)
		Local	stream:TStream
		Local	f$,p,a$,b$
' defaults		
		Local wh=ClientHeight(Desktop())-80'32
		Local ww=wh
		Local wx=(ClientWidth(Desktop())-ww)/2
		Local wy=(ClientHeight(Desktop())-wh)/2
		winsize.set( wx,wy,ww,wh )
		quickenabled=True
		debugenabled=True
		guienabled=True	
		vsplitpos=ww-200
'		hsplitpos=wh-200
' read ini
		stream=ReadFile(inifile$)
		If Not stream Return
		optionsreq.read(stream)		
		While Not stream.Eof()
			f$=stream.ReadLine()
			p=f.find("=")
			If p=-1 Continue
			a$=f[..p]
			b$=f[p+1..]
			Select a$
				Case "file_recent"
					recentfiles.addlast b$
				Case "file_open"
					openlist.addlast b$
				Case "prg_quick"
					quickenabled=Int(b$)
				Case "prg_debug"
					debugenabled=Int(b$)
				Case "prg_gui"
					guienabled=Int(b$)
				Case "cmd_line"
					cmdline=b$
				Case "prg_locked"
					openlock=b$
				Case "nav_tab"
					navtab=Int(b$)
				Case "win_size"
					winsize.FromString(b$)
				Case "win_max"
					winmax=Int(b$)
'				Case "hsplit_pos"
'					hsplitpos=Int(b$)
				Case "vsplit_pos"
					vsplitpos=Int(b$)
				Case "proj_node"
'					projlist.AddLast b$
					Local projdata:TList=New TList
					projdata.AddLast b
					projlist.AddLast projdata
			End Select
		Wend
		stream.close		
	End Method
	
	Method WriteConfig(inifile$)
		Local	panel:TToolPanel
		Local	stream:TStream
		Local	project:TFolderNode
		Local	f$
		
		navtab=navbar.SelectedView()
		stream=WriteFile(inifile)
		If Not stream Return
' options
		optionsreq.write(stream)
' defaults		
		stream.WriteLine "[Defaults]"
		stream.WriteLine "prg_quick="+quickenabled
		stream.WriteLine "prg_debug="+debugenabled
		stream.WriteLine "prg_gui="+guienabled
		stream.WriteLine "nav_tab="+navtab
		stream.WriteLine "win_size="+winsize.ToString()
		stream.WriteLine "win_max="+winmax
'		stream.WriteLine "hsplit_pos="+hsplit.pos
		stream.WriteLine "vsplit_pos="+vsplit.pos
		stream.WriteLine "cmd_line="+cmdline
		If lockedpanel stream.WriteLine "prg_locked="+lockedpanel.path
		For f$=EachIn recentfiles
			stream.WriteLine "file_recent="+f$
		Next
		For panel=EachIn panels
			f$=panel.path
			If f$ And Not IsTempPath(f$) stream.WriteLine "file_open="+f$
		Next
		projects.write(stream,"")	
		stream.close
	End Method
	
	Method Quit()
		Local	panel:TToolPanel
		Local	mypanels:TToolPanel[]
		Local	cancel	
		WriteConfig inifile
		mypanels=panels
		cancel=False
		For panel=EachIn mypanels
			If panel.invoke("CLOSE") cancel=True
		Next
		If Not cancel running=False
	End Method
		
	Method DebugExit()
		If debugcode 
			debugcode.Edit		'restore cursor etc.	
			debugcode=Null
		EndIf
		SetMode EDITMODE
	End Method

	Method WriteDebug(text$)
		If Not output output=TOutputPanel.Create(Self,options.outputstyle,options.errorstyle)
		output.WritePipe text
	End Method
			
	Method DebugSource(path$,line,column)
		Local	code:TOpenCode
		path=FullPath(path)
		code=TOpenCode(OpenSource(path))
		If code=Null
			Notify("Failed to Open "+path)
			Return
		EndIf
		code.debug(line,column)		
	End Method
	
	Method SetMode(m)
		If editormode=m Return
		editormode=m
		RefreshToolbar
		If editormode=DEBUGMODE
			navtab=navbar.SelectedView()
			SelectView debugview
		Else
			SelectView navtab		
		EndIf
	End Method
	
	Method Help(url$)
		helppanel.Go url
	End Method

	Method RefreshToolbar()		
		Local	i
' sourceedit buttons
		If THelpPanel(CurrentPanel)
			DisableGadgetItem toolbar,2
		Else
			EnableGadgetItem toolbar,2
		EndIf
		If TOpenCode(CurrentPanel)
			EnableGadgetItem toolbar,3
			For i=5 To 8
				EnableGadgetItem toolbar,i
			Next
		Else
			DisableGadgetItem toolbar,3
			For i=5 To 8
				DisableGadgetItem toolbar,i
			Next			
		EndIf
' debug buttons
		If editormode=DEBUGMODE And debugtree.cancontinue
			For i=12 To 14
				EnableGadgetItem toolbar,i
			Next
		Else
			For i=12 To 14
				DisableGadgetItem toolbar,i
			Next
		EndIf
' stop button		
		If output And output.process
			EnableGadgetItem toolbar,15
		Else
			DisableGadgetItem toolbar,15
		EndIf		
	End Method
	
	Method IsSourceOpen(path$)
		Local	panel:TToolPanel
		Local	p$
		p$=FullPath(path)
		For panel=EachIn panels
			If panel.path=p Return True
		Next
	End Method
	
	Method OpenSource:Object(path$)
		Local	panel:TToolPanel
		Local	ext$,p$

		If path$="." 
			path$=RequestFile("Open File",filefilters(),0)
			If path$="" Return
		EndIf
' check if already open
		p$=FullPath(path).ToLower()
		For panel=EachIn panels
			If panel.path.ToLower()=p
				SelectPanel panel
				Return TOpenCode(panel)
			EndIf
		Next
' open based on extension		
		If path
			OpenProgress "Loading "+StripDir(path)
			path=FullPath(path)
			panel=TToolPanel(OpenObject(path))
			CloseProgress
		Else
'			DebugStop
'			code=TBMXCode.Create("",Self)
		EndIf

		If panel
			AddRecent panel.path
			SelectPanel Panel
'			panel.invoke "ACTIVATE"
		EndIf
					
		Return panel
	End Method
	
	Method AddRecent(path$)
		Local	f$
		For f$=EachIn recentfiles
			If f$=path$ recentfiles.Remove(f$);Exit
		Next
		recentfiles.AddFirst(path$)
		RefreshRecentFiles
		UpdateWindowMenu window
	End Method
	
	Method RefreshRecentFiles()
		Local	n,f$
		Local	m:TGadget
		For m=EachIn recentmenus
			FreeMenu m
		Next
		n=Min(recentfiles.count(),16)
		recentmenus=New TGadget[n]
		n=0
		For f$=EachIn recentfiles
			recentmenus[n]=CreateMenu(f$,MENURECENT+n,recentmenu)
			n:+1
			If n=16 Exit
		Next
	End Method

	Method GetCommandLine$()
		Return cmdline
	End Method

	Method SetCommandLine(text$)
		cmdline=text
	End Method
	
	Method SetStatus(text$)
		SetStatusText window,text
	End Method

	Method Execute(owner:TTool,cmd$,mess$="",post$="",home=True)
		If Not output output=TOutputPanel.Create(Self,options.outputstyle,options.errorstyle)
		output.execute owner,cmd$,mess$,post$,home
	End Method

	Method SelectError(path$,column,line)
		Local	panel:TToolPanel,found
		For panel=EachIn panels
			If panel.path=path found=True;Exit
		Next
		If Not found panel=TToolPanel(OpenSource(path))
		If panel
			SelectPanel panel
			panel.Invoke "GOTO",String(line)
		EndIf
	End Method
	
	Method AddPanel(tabpanel:TToolPanel)
		Local	panel:TGadget,index
		index=CountGadgetItems(tabbar)
		If panels.length<=index panels=panels[..index+1]
		AddGadgetItem(tabbar,tabpanel.name$,True)
		
		panel=CreatePanel(0,0,ClientWidth(tabbar),ClientHeight(tabbar),tabbar,0)	'name		
		SetGadgetLayout panel,1,1,1,1
		tabpanel.panel=panel
		
		tabpanel.index=index
		panels[index]=tabpanel
'		SelectPanel tabpanel moved to caller
		eventhandlers.addlast tabpanel
	End Method

	Method RemovePanel(tabpanel:TToolPanel)
		Local p:TToolPanel[]
		Local index
		eventhandlers.remove tabpanel
' unset debugcode
		If debugcode=tabpanel debugcode=Null		
' activate next panel
		If tabpanel=activepanel activepanel=helppanel
		If tabpanel=lockedpanel lockedpanel=Null
		If tabpanel=currentpanel
			index=tabpanel.index+1
			If index>=panels.length index=panels.length-2
			SelectPanel panels[index]
		EndIf
' remove from array
		p=panels
		panels=panels[..panels.length-1]
		For index=tabpanel.index To panels.length-1
			panels[index]=p[index+1]
			panels[index].index=index
		Next
' remove gadget
		FreeGadget tabpanel.panel
		RemoveGadgetItem tabbar,tabpanel.index
		tabpanel.panel=Null
	End Method
		
	Method SetRequester(req:TRequester)
		activerequester=req
		If req=Null SelectPanel currentpanel
	End Method
	
	Method SetTitle(title$="")
		If title title=" - "+title
		SetGadgetText window,AppTitle+title
	End Method
	
	Method SelectPanel(panel:TToolPanel)	
		Local	current:TToolPanel
		If Not panel
			DebugLog "editor.SelectPanel with null!"
			Return
		EndIf
		current=currentpanel
		currentpanel=panel
		ShowGadget panel.panel
		SelectGadgetItem tabbar,panel.index
		currentpanel.Invoke "SHOW"
		If panel.active activepanel=panel
		If current And current<>currentpanel HideGadget current.panel
		RefreshToolbar
	End Method
		
	Method RefreshPanel(panel:TToolPanel)	'call after a name change
		ModifyGadgetItem( tabbar,panel.index,panel.name )	
	End Method
	
	Function OutsideDesktop(winrect:TRect)
		Local	desk:TGadget
		Local	x,y,w,h
		desk=Desktop()
		x=GadgetX(desk)
		y=GadgetY(desk)
		w=GadgetWidth(desk)
		h=GadgetHeight(desk)
'		DebugLog "Desktop="+x+","+y+","+w+","+h
		Return winrect.IsOutside(x,y,w,h)
	End Function

	Method SetCodeNode(code:TDataNode)
		Local node:TDataNode
		If coderoot.kids.count() node=TDataNode(coderoot.kids.First())
		If node=code Return
		If node node.Detach
		If code
			coderoot.Append code
			coderoot.Refresh 
			coderoot.Open
			code.Open
		EndIf
	End Method
	
'	Method AddView(datanode:TDataNode)
'		Return navbar.AddView(datanode)
'	End Method

	Method AddNode(datanode:TDataNode)
		root.Append datanode
'		Return navbar.AddView(datanode)
	End Method

	Method SelectView(viewid)
		Return navbar.SelectView(viewid)
	End Method

	Method ResetEditor(name$,about$)		
'		Local	open:TOpenCode
		Local	i,dir$,pname$,p
		Local	stream:TStream
		Local	temppath$
		Local	cfgpath$

		AppTitle=name		
		Try
			apppath=BlitzMaxPath()
		Catch err$
			Notify "Could not find BlitzMax folder"	' (Bin/bcc), please Reinstall~nappdir="+AppDir
			apppath=AppDir
		EndTry

		appname=name
		appabout=about
		
		temppath=AppPath+"/tmp"		
		If FileType(temppath)=0 
			If Not CreateDir(temppath) Notify "Unable to create temp directory "+temppath
		EndIf
		SetProperty "TempDir",temppath

		cfgpath=AppPath+"/cfg"		
		If FileType(cfgpath)=0 
			If Not CreateDir(cfgpath) Notify "Unable to create config directory "+cfgpath
		EndIf
		SetProperty "ConfigDir",cfgpath
	
'		inifile=AppPath+"/"+appname+".ini"
		inifile=cfgpath+"/"+appname+".ini"

		cmdlinereq=TCmdLineRequester.Create(Self)
'		syncmodsreq=TSyncModsRequester.Create(Self)
		newrequester=TNewRequester.Create(Self)
		gotoreq=TGotoRequester.Create(Self)
		findreq=TFindRequester.Create(Self)
		replacereq=TReplaceRequester.Create(Self)

		optionsreq=New TOptionsRequester.CreateOptionsRequester(Self)
		hostoptions=optionsreq.rootpage
		
		options=New TEditorOptions.CreateEditorOptions(hostoptions)
		optionsreq.OpenPage options

		hotkeys=New THotkeyOptions.CreateHotkeyOptions(hostoptions)

		projectreq=TProjectRequester.Create(Self)
'		projectprops=TProjectProperties.Create(Self)
		
		root=TDataNode.Create("Home")
		docroot=root.AddNode("Documentation")
		docroot.Open

		projects=TProjects.CreateProjects(Self)		
		root.Append projects
		projects.Open

		window=CreateWindow(AppTitle,0,0,100,100,Null,15|WINDOW_HIDDEN|WINDOW_ACCEPTFILES)	

		InitMainMenu()

		InitializePlugins()
'		InitHelpMenu()


		ReadConfig inifile

		InvokePlugins("RESET",Self)

		RefreshRecentFiles
		
		If quickenabled CheckMenu quickenable
		If debugenabled CheckMenu debugenable
		If guienabled CheckMenu guienable

		If OutsideDesktop(winsize)
			winsize.set(20,20,760,540)		
		EndIf	
		
		SetGadgetShape window,winsize.x,winsize.y,winsize.w,winsize.h
'		window=CreateWindow(AppTitle,winsize.x,winsize.y,winsize.w,winsize.h,Null,15|WINDOW_HIDDEN|WINDOW_ACCEPTFILES)	
		If winmax MaximizeWindow(window)

		toolbar=CreateToolBar("incbin::toolbar.png",0,0,0,0,window )
		SetToolBarTips toolbar,["New","Open","Close","Save","","Cut","Copy","Paste","Find","","Build","Build And Run","Step","Step In","Step Out","Stop"		,"","Home","Back","Forward"		]

		If options.showtoolbar.selected()
			tooly=GadgetHeight(toolbar)
		Else
			HideGadget toolbar
			tooly=0
		EndIf

?MacOS
		client=window
?
		If Not client
			client=CreatePanel(2,tooly,ClientWidth(window)-4,ClientHeight(window)-tooly-2,window,4)
			SetGadgetLayout client,1,1,1,1
		EndIf

		tabbar=CreateTabber(0,0,ClientWidth(client),ClientHeight(client),client)
		SetGadgetLayout tabbar,1,1,1,1
	
		debugtree=TDebugTree.CreateDebugTree(Self,options.debuggeropenfiles)
		debugger=debugtree

		coderoot=TDataNode.Create("Code")
		coderoot.Open

		navbar=TNavBar.CreateNavbar(Self,client,options.navstyle)
		navbar.AddView root
		navbar.AddView coderoot
	
		debugview=navbar.AddView(debugtree)
		navbar.SelectView 0

		Local side=options.navside.Selected()
		vsplit=TSplitter.Create(TSplitter.VERTICAL,vsplitpos,side,tabbar,navbar.tabber,client)

		AddHandler navbar
		AddHandler vsplit
	
		helppanel=THelpPanel.Create(Self)

		output=TOutputPanel.Create(Self,options.outputstyle,options.errorstyle)		

		activepanel=helppanel
'		InitHotkeys

		ShowGadget window	
		RefreshAll
		PollSystem	'allow repaint
' open files from .ini restorelist		
		If options.restoreopenfiles.Selected()
			For Local f$=EachIn openlist
				Local open:TToolPanel=TToolPanel(OpenSource(f$))		'Code(OpenSource(f$))
'				If f$=openlock open.SetLocked(True) 
				If open And f$=openlock open.Invoke "LOCK"	'SetLocked(True) 
			Next
		EndIf
' open files specified in command line		
		For i=1 To AppArgs.length-1
			'open=TOpenCode(
			OpenSource(AppArgs[i])')
		Next
' scan projects in projlist		
		Local pdata:TList
		For pdata=EachIn projlist
			projects.AddProject pdata
		Next		
'		For pname$=EachIn projlist
'			p=pname.Find("|")
'			If p<>-1
'				projects.AddProject pname[..p],pname[p+1..]
'			EndIf
'		Next
		SetMode EDITMODE
		PollSystem
		running=True
	End Method

	Method AddMenuItem:TGadget(text$,tag,parent:TGadget)
		Local item:TGadget
		Local b:THotkeyButton
		Local n$,hotkey,modifier
		item=CreateMenu(text,tag,parent)	',hotkey,modifier)
		n$=text
		n=n.Replace("...","")
		n=n.Replace("&","")
		If n hotkeys.AddMenuitem(n,item,tag)
'		If n b=hotkeys.FindHotkey(n)
'		If b hotkey=b.keycode;modifier=b.modifier
'		item=CreateMenu(text,tag,parent,hotkey,modifier)
'		If b b.SetItem
		Return item
	End Method
		
	Method DisableHotkeys()
		Local item:TGadget
		Local b:THotkeyButton
		For item=EachIn hotkeys.itemmap.keys()
			b=THotkeyButton(hotkeys.itemmap.ValueForKey(item))
			If b 
				SetGadgetHotKey item,0,0			
				If b.keycode2
'					SetHotKeyEvent b.keycode2,b.modifier2,CreateEvent(EVENT_MENUACTION,Null,b.tag)
				EndIf
			EndIf
		Next
		UpdateWindowMenu window
	End Method

	Method RethinkMainMenu()
		Local item:TGadget
		Local b:THotkeyButton
		For item=EachIn hotkeys.itemmap.keys()
			b=THotkeyButton(hotkeys.itemmap.ValueForKey(item))
			If b 
				SetGadgetHotKey item,b.keycode,b.modifier			
				If b.keycode2
					SetHotKeyEvent b.keycode2,b.modifier2,CreateEvent(EVENT_MENUACTION,Null,b.tag)
				EndIf
			EndIf
		Next
		UpdateWindowMenu window
	End Method
	
	Method InitMainMenu()
?MacOS
		Const MENUMOD=MODIFIER_APPLE
?Win32
		Const MENUMOD=MODIFIER_CONTROL
?Linux
		Const MENUMOD=MODIFIER_CONTROL
?
		filemenu=AddMenu("&File")
		AddMenuItem "&New",MENUNEW,filemenu
		AddMenuItem "&Open...",MENUOPEN,filemenu
		recentmenu=CreateMenu("Open &Recent",0,filemenu)
		AddMenuItem "&Close",MENUCLOSE,filemenu
		AddMenuItem "",0,filemenu
		AddMenuItem "&Save",MENUSAVE,filemenu
		AddMenuItem "Save &As",MENUSAVEAS,filemenu
		AddMenuItem "Save A&ll",MENUSAVEALL,filemenu
		AddMenuItem "",0,filemenu
		AddMenuItem "&Next File",MENUNEXT,filemenu
		AddMenuItem "&Previous File",MENUPREV,filemenu
		AddMenuItem "",0,filemenu
		AddMenuItem "IDE Options...",MENUOPTIONS,filemenu
		AddMenuItem "",0,filemenu
		AddMenuItem "Print...",MENUPRINT,filemenu
' not on OSX
		AddMenuItem "",0,filemenu
		AddMenuItem "E&xit",MENUQUIT,filemenu

		editmenu=AddMenu("&Edit")
		AddMenuItem "&Undo",MENUUNDO,editmenu		
		AddMenuItem "&Redo",MENUREDO,editmenu
		AddMenuItem "",0,editmenu
		AddMenuItem "Cu&t",MENUCUT,editmenu
		AddMenuItem "&Copy",MENUCOPY,editmenu
		AddMenuItem "&Paste",MENUPASTE,editmenu
		AddMenuItem "",0,editmenu
		AddMenuItem "Select &All",MENUSELECTALL,editmenu
		AddMenuItem "",0,editmenu
		AddMenuItem "Block Indent",MENUINDENT,editmenu
		AddMenuItem "Block Outdent",MENUOUTDENT,editmenu
		AddMenuItem "",0,editmenu
		AddMenuItem "&Find...",MENUFIND,editmenu

		AddMenuItem "Find Next",MENUFINDNEXT,editmenu
		AddMenuItem "&Replace...",MENUREPLACE,editmenu
		AddMenuItem "&Goto Line...",MENUGOTO,editmenu

		projectmenu=AddMenu("&Project")
		AddMenuItem "&Build",MENUBUILD,projectmenu
		AddMenuItem "Build and &Run",MENURUN,projectmenu
		AddMenuItem "Command &Line...",MENUCOMMANDLINE,projectmenu
		AddMenuItem "",0,projectmenu
		AddMenuItem "&Step",MENUSTEP,projectmenu
		AddMenuItem "Step &In",MENUSTEPIN,projectmenu
		AddMenuItem "Step &Out",MENUSTEPOUT,projectmenu
		AddMenuItem "&Halt",MENUSTOP,projectmenu
		
		Local optionsmenu:TGadget=CreateMenu("Build Options",0,projectmenu)
		quickenable=AddMenuItem("Quick Build",MENUQUICKENABLED,optionsmenu)
		debugenable=AddMenuItem("Debug Build",MENUDEBUGENABLED,optionsmenu)
		guienable=AddMenuItem("Build GUI App",MENUGUIENABLED,optionsmenu)
		
		AddMenuItem "",0,projectmenu
		AddMenuItem "&Lock Build File",MENULOCKBUILD,projectmenu
		AddMenuItem "&Unlock Build File",MENUUNLOCKBUILD,projectmenu

		AddMenuItem "",0,projectmenu
		AddMenuItem "&Manage Projects...",MENUPROJECTMANAGER,projectmenu

		toolsmenu=AddMenu("&Tools")

		helpmenu=AddMenu("&Help")
		AddMenuItem "&Quick Help",MENUQUICKHELP,helpmenu
		AddMenuItem "Help &Index",MENUHELPINDEX,helpmenu
		AddMenuItem "",0,helpmenu
		AddMenuItem "&Home",MENUHOME,helpmenu
		AddMenuItem "&Back",MENUBACK,helpmenu
		AddMenuItem "&Forward",MENUFORWARD,helpmenu
		AddMenuItem "&About "+appname,MENUABOUT,helpmenu

	End Method

	Method RunCode()
		If editormode=DEBUGMODE
			output.go
			Return
		EndIf
		SaveAll
		If lockedpanel
			lockedpanel.invoke "RUN"
		Else
			activepanel.invoke "RUN"
		EndIf
	End Method
	
	Method BuildCode()
		SaveAll
		If lockedpanel
			lockedpanel.invoke "BUILD"
		Else
			activepanel.invoke "BUILD"
		EndIf
	End Method
	
	Method ProcessError$(line$)
		If editormode=DEBUGMODE
			line=debugger.Process(line)
			If Not line Return

'			For Local plugin:TPlugin=EachIn pluginlist
'				line=plugin.Debug(line)
'				If line="" Return
'			Next
		EndIf
		Return line
	End Method
						
	Method SaveAll()
		Local	panel:TToolPanel
		For panel=EachIn panels
			panel.invoke "QUICKSAVE"						
		Next
	End Method
	
	Method RefreshHelp()
	End Method
	
	Method RefreshAll()
		Local	panel:TToolPanel
' flip navbar
		Local navside=options.navside.Selected()
		vsplit.SetFlip navside
' hide/show toolbar
		If options.showtoolbar.selected()
			If GadgetHidden(toolbar) 
				tooly=GadgetHeight(toolbar)
				ShowGadget toolbar
				SetGadgetShape client,0,tooly,ClientWidth(window),ClientHeight(window)-tooly				
'				SetGadgetShape tabbar,0,tooly,clientwidth(window),clientheight(window)-tooly
			EndIf
		Else
			If Not GadgetHidden(toolbar)
				tooly=0
				HideGadget toolbar
				SetGadgetShape client,0,tooly,ClientWidth(window),ClientHeight(window)-tooly
'				SetGadgetShape tabbar,0,tooly,clientwidth(window),clientheight(window)-tooly
			EndIf
		EndIf
' refresh panels
		For panel=EachIn panels
			panel.invoke "REFRESH"
		Next
' refresh navbar
		navbar.invoke "REFRESH"
' refresh menu hotkeys
		RethinkMainMenu()
	End Method

	Method SnapshotWindow()
		If WindowMaximized(window)
			winmax=True
		Else
			If Not WindowMinimized(window)
				winmax=False
				winsize.x=GadgetX(window)
				winsize.y=GadgetY(window)
				winsize.w=GadgetWidth(window)
				winsize.h=GadgetHeight(window)
'				DebugLog "winsize="+winsize.x+","+winsize.y+","+winsize.w+","+winsize.h
			EndIf
		EndIf
	End Method
		
	Method MainMenu(menu)
		Local	index

		Select menu
			Case MENUNEW
				newrequester.Show
			Case MENUOPEN
				OpenSource "."
			Case MENUCLOSE
				currentpanel.invoke "CLOSE"
			Case MENUSAVE
				currentpanel.invoke "SAVE"
			Case MENUSAVEAS			
				currentpanel.invoke "SAVEAS"
			Case MENUSAVEALL
				SaveAll
			Case MENUPRINT
				currentpanel.invoke "PRINT"					
			Case MENUQUIT
				Quit
			Case MENUGOTO
				gotoreq.Show
			Case MENUFIND
				currentpanel.invoke "FIND"
			Case MENUFINDNEXT
				currentpanel.invoke "FINDNEXT"
			Case MENUREPLACE
				replacereq.Show
			Case MENUUNDO currentpanel.invoke "UNDO"
			Case MENUREDO currentpanel.invoke "REDO"

			Case MENUCUT currentpanel.invoke "CUT"
			Case MENUCOPY currentpanel.invoke "COPY"
			Case MENUPASTE currentpanel.invoke "PASTE"
			Case MENUSELECTALL currentpanel.invoke "SELECTALL"
										
			Case MENUBUILD BuildCode 
			Case MENURUN RunCode
			
			Case MENUSTEP If output output.stepover
			Case MENUSTEPIN If output output.stepin
			Case MENUSTEPOUT If output output.stepout
			Case MENUSTOP If output output.stop

			Case MENULOCKBUILD activepanel.invoke "LOCK"
			Case MENUUNLOCKBUILD If lockedpanel lockedpanel.invoke "UNLOCK"
			
			Case MENUCOMMANDLINE cmdlinereq.Show
			
			Case MENUQUICKENABLED
				If quickenabled
					quickenabled=False
					UncheckMenu quickenable							
				Else
					quickenabled=True
					CheckMenu quickenable
				EndIf
				UpdateWindowMenu window

			Case MENUDEBUGENABLED
				If debugenabled
					debugenabled=False
					UncheckMenu debugenable							
				Else
					debugenabled=True
					CheckMenu debugenable
				EndIf
				UpdateWindowMenu window
				
			Case MENUGUIENABLED
				If guienabled
					guienabled=False
					UncheckMenu guienable							
				Else
					guienabled=True
					CheckMenu guienable
				EndIf
				UpdateWindowMenu window
				
			Case MENUPROJECTMANAGER
				projectreq.Open projects
			Case MENUSHOWCONSOLE
				If output output.Open

			Case MENUOPTIONS
				optionsreq.Show
				
			Case MENUNEXT
				If Not currentpanel Return
				index=currentpanel.index+1
				If index=panels.length index=0
				SelectPanel panels[index]

			Case MENUPREV
				If Not currentpanel Return
				index=currentpanel.index-1
				If index<0 index=panels.length-1
				SelectPanel panels[index]
			
			Case MENUQUICKHELP 
				currentpanel.invoke "HELP"
			Case MENUHELPINDEX 
				helppanel.Index
				SelectPanel helppanel			
			Case MENUHOME
				helppanel.Home
				SelectPanel helppanel
			Case MENUBACK
				helppanel.Back
				SelectPanel helppanel
			Case MENUFORWARD
				helppanel.Forward
				SelectPanel helppanel
			Case MENUABOUT
				Notify appabout

			Case MENUINDENT
				currentpanel.invoke "INDENT"
			Case MENUOUTDENT
				currentpanel.invoke "OUTDENT"

			Case MENUDOCMODS
				RefreshHelp
				
			Case MENUNEWVIEW
				navbar.invoke "NEWVIEW"
				
		End Select
		
		If menu>=MENURECENT And menu<MENUCUSTOM
			Local f$=String(recentfiles.ValueAtIndex(menu-MENURECENT))
			If f$ OpenSource f$
		EndIf
		
		If menu>=MENUCUSTOM
			TPlugin.InvokeCommand menu
		EndIf	
	End Method
	
	Method Invoke(command$,argument:Object=Null)
		Select command
			Case "NAVIGATE"
				helppanel.Invoke command,argument
			Case "COMMAND"
				Notify "argument="+String(argument)
		End Select
	End Method

	Method OnEvent()
		Local	handler:TEventHandler
		Local	requester:TRequester
		Local	src:TGadget,file$
		Local	index
'		DebugLog currentevent.ToString()
		If activerequester
			activerequester.OnEvent
			Return
		EndIf

		For handler=EachIn eventhandlers
			handler.OnEvent()
		Next

		Select EventID()
			Case EVENT_GADGETACTION
				Select EventSource()
					Case toolbar
						Select EventData()
							Case 0 newrequester.Show
							Case 1 OpenSource "."
							Case 2 currentpanel.invoke "CLOSE"
							Case 3 currentpanel.invoke "SAVE"
							Case 5 currentpanel.invoke "CUT"
							Case 6 currentpanel.invoke "COPY"
							Case 7 currentpanel.invoke "PASTE"
							Case 8 currentpanel.invoke "FIND"
							Case 10 BuildCode
							Case 11 RunCode
							Case 12 If output output.stepover
							Case 13 If output output.stepin
							Case 14 If output output.stepout
							Case 15 If output output.stop
							Case 17 helppanel.Home;SelectPanel helppanel
							Case 18 helppanel.Back;SelectPanel helppanel
							Case 19 helppanel.Forward;SelectPanel helppanel
						End Select
						
					Case tabbar
						index=EventData()
						If index>=0 And index<panels.length
							SelectPanel panels[index]
						EndIf
				End Select
				
			Case EVENT_WINDOWACTIVATE
				SelectPanel currentpanel
				
			Case EVENT_WINDOWCLOSE
				src=TGadget(EventSource())
				For requester=EachIn eventhandlers
					If src=requester.window requester.Hide
				Next
				If src=window Quit

			Case EVENT_WINDOWMOVE
				If EventSource()=window SnapshotWindow				
				
			Case EVENT_WINDOWSIZE
				If EventSource()=window 
					SnapshotWindow
					vsplit.Resize
				EndIf
				
			Case EVENT_WINDOWACCEPT
				OpenSource EventText()

			Case EVENT_MENUACTION
				Local o:Object
				Local src:Object
				o=EventExtra()
				If o
					src=EventSource()
					DebugLog CurrentEvent.ToString()
					If TTool(o) TTool(o).invoke(EventData())
				Else
					MainMenu EventData()
				EndIf
				
		End Select
	End Method
End Type
